# -*- coding: utf-8 -*-
"""
Created on Thu May 13 11:00:23 2021

@author: Hu Yue
@email: hhhuyue@gmail.com

Note:
"""
import logging
import pandas as pd
from math import isnan
import numpy as np



import json

def get_bt_delta(S,K,T,sigma,cp_type):

        if T == 0:
            return cp_type

        s_now = S
        S = s_now * 1.0005
        price_1 = bt_model(S,K,T,sigma,cp_type)
        print("price_1:",price_1)

        S = s_now * 0.9995
        price_2 = bt_model(S,K,T,sigma,cp_type)
        print("price_2:",price_2)
        S = s_now

        delta = (price_1 - price_2) / (s_now * 0.001)
        print("delta:",delta)
        return delta


def bt_model(S,K,T,sigma,cp_type):
    
        steps = 50
        r = 0.0335
        q = 0
        delta_t = T / steps
        u = np.exp(sigma * np.sqrt(delta_t))
        d = 1 / u
        P = (np.exp((r - q) * delta_t) - d) / (u - d)
        #print("u:",u)
        #print("d:",d)
        #print("p:",P)
        prices = np.zeros(steps + 1)  # 生成最后一列的股票价格空数组
        values = np.zeros(steps + 1)  # 生成最后一列的期权价值空数组

        prices[0] = S * d ** steps
        values[0] = np.maximum(cp_type * (prices[0] - K), 0)

        for i in range(1, steps + 1):
            prices[i] = prices[i - 1] * (u ** 2)
            values[i] = np.maximum(cp_type * (prices[i] - K), 0)
        #print("prices:",prices)
        #print("values:",values)
        discount = np.exp(-r * delta_t)
        for j in range(steps, 0, -1):
            for i in range(0, j):
                prices[i] = prices[i + 1] * d
                bt_value = cp_type * (prices[i] - K)
                values[i] = np.maximum((P * values[i + 1] + (1 - P) * values[i]) * discount, bt_value)

        option_price = values[0]

        return option_price



class MyEncoder(json.JSONEncoder):
   def default(self,obj):
       if isinstance(obj,np.integer):
           return int(obj)
       elif isinstance(obj, np.floating):
           return float(obj)
       elif isinstance(obj,np.ndarray):
           return obj.tolist()
       else:
           return super(MyEncoder,self).default(obj)

def get_hedged_retDT1(future_,option,params,filepath):
    future = future_.copy()
    start_date = params['start_date']
    end_date = params['end_date']

    
    if len(future) ==0 or len(option) ==0:
       logging.error("期权{}或证券{}没有相应的数据啦！".format(params['contract_code'],params['code']))
       return {}
    
    
    option.set_index(['date'],inplace=True,drop=True)
    future.set_index(['date'],inplace=True,drop=True)
    #option_info.loc[:,'spread'] = pd.eval('option_info.BestOffer-option_info.BestBid')
    #option_info['ImpliedVolatility'][option_info['ImpliedVolatility'] <-99] =np.nan  #不需要去掉缺失，因为没有缺失
    #option_info.loc[:,'midprice']  =pd.eval('option_info.BestOffer+option_info.BestBid') /2
    #option_info['Strike'] = option_info.Strike/1000
    
    #option_info.loc[:,'ImpliedVolatility'] = option_info.loc[:,'ImpliedVolatility'].fillna(method='ffill')
    
    start_price = future.loc[start_date,'future_price']
    
    sigma =option.loc[start_date,'iv']
    delta = option.loc[start_date,'delta']
    time2mat = option.loc[start_date,'time2mat']
    cptype = option.loc[start_date,'cp_type']
    K = option.loc[start_date,'strike_price']
    start_cost = option.loc[start_date,'option_price'] 
    end_price = future.loc[end_date,'future_price']
    endcost1 =  option.loc[end_date,'option_price']
    
    rate = 3.35/365/100/100
        
    # 计算每天的对冲成本和总的对冲成本
    hedge_info = future.join(option.drop(['code'],axis=1))
         
    hedge_info.sort_index(inplace=True)
    for idx,row in hedge_info.iterrows():
        
        hedge_info.loc[idx,'adjst_Delta'] = get_bt_delta(row['future_price'],row['strike_price'],row['time2mat']/365,row['iv']/100,row['cp_type'])
    
    #hedge_info.loc[:,'sign'] = (hedge_info['CallPut']=='C')*1
    #hedge_info.loc[:,'sign_up'] = (hedge_info['future_price']>hedge_info['strike_price'])*1
    #hedge_info.loc[:,'sign_down'] = (hedge_info['future_price']<hedge_info['strike_price'])*1
    
    hedge_info['sign'] = hedge_info['delta'].apply(lambda x:isnan(x)*1)
    #hedge_info['cp_type_'] = (hedge_info['cp_type']==1)*1
    #hedge_info['delta'][hedge_info['sign']==1] = hedge_info['adjst_Delta']
    #pd.eval('hedge_info.cp_type_*(1-hedge_info.sign_down)+(1-hedge_info.cp_type_)*(hedge_info.sign_up-1)') 
    #print(hedge_info['delta'])
    hedge_info['diff_price'] = hedge_info['future_price'].shift(-1)-hedge_info['future_price']
    hedge_info['PnL']= pd.eval('hedge_info.diff_price*hedge_info.delta')*(-1)
    hedge_info['days_diff'] = hedge_info['time2mat'].shift(-1) -hedge_info['time2mat']
    hedge_info['interest'] = (-start_cost + hedge_info['delta']*hedge_info['future_price']) * rate*hedge_info['days_diff']
    
    # 记录当天的损益
    hedge_info.loc[:,'date_str'] = hedge_info.index.values
    hedge_info['date_str'] = hedge_info['date_str'].apply(lambda x: x.strftime("%Y-%m-%d"))
    hedge_info['stock_gain'] = -(hedge_info['future_price'].shift(-1) - hedge_info['future_price'])*hedge_info['delta']
    hedge_info['option_gain'] = hedge_info['option_price'].shift(-1) - hedge_info['option_price']
    hedge_info['total_gain'] = hedge_info['stock_gain'] + hedge_info['option_gain']
    hedge_info = hedge_info.round({"stock_gain":5,"option_gain":5,"total_gain":5})
    hedgeret = hedge_info['PnL'].sum()
    interest2 = 0#hedge_info['interest'].sum()
    
    daily_pnl = np.array(hedge_info[['date_str','stock_gain','option_gain','total_gain']]).tolist()
    #print("cptype:",cptype)
    #print("end_price:",end_price)
    #print("K:",K)
    endcost2 = max(cptype*(end_price-K),0)
           
    mat = (option.loc[end_date,'time2mat']>0)*1  
    endcost = mat*endcost2 +(1-mat)*endcost1
    # 这里的spread怎么处理呢
    PnL = start_cost - endcost - hedgeret -interest2 #- 0.35*option_info.loc[start_date,'spread'] 
    ret ={
        "start_cost":start_cost,
        #"startspred":option_info.loc[start_date,'spread'],
        "startvega":option.loc[start_date,'vega'],
        "startprice":start_price,
        "endcost1":endcost1,
        "endcost2":endcost2,
        "K":K,
        "endprice":end_price,
        "hedgeret":hedgeret,
        "mat":mat,
        #"endspred":option_info.loc[end_date,'spread'],
        "Code":params['code'],
        "lastday": option.loc[start_date,'final_date'].strftime("%Y-%m-%d"),
        "time2mat":time2mat,
        "startdate":start_date.strftime("%Y-%m-%d"),
        "end_date":end_date.strftime("%Y-%m-%d"),
        "Contract_Code":params['contract_code'],
        "VOL":option.loc[start_date,'vol'],
        "IV":sigma,
        "Gamma":option.loc[start_date,'gamma'],
        "Delta":delta,
        "endcost":endcost,
        "PnL":PnL,
        "cptype":cptype,
        "interest2":interest2,
        "daily_pnl":daily_pnl
        }

    if ret:
       with open(filepath,"a") as f:
           f.write(json.dumps(ret,cls=MyEncoder))
           f.write("\n")
    return ret,hedge_info